package com.example.utils;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import com.example.exception.CustomException;
import com.google.code.kaptcha.Producer;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.FastByteArrayOutputStream;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@Component
@EnableScheduling
public class ValidateCodeUtils {

    private static Producer staticProducer;

    @Resource
    private Producer producer;

    @PostConstruct
    public void init() {
        staticProducer = producer;
    }

    private static final Map<String, Date> CODE_MAP = new ConcurrentHashMap<>();

    /**
     * 获取验证码并缓存
     */
    public static Map<String, Object> getValidateCode() {
        String code = RandomUtil.randomNumbers(4);
        // 返回图片的base64编码
        try (FastByteArrayOutputStream outputStream = new FastByteArrayOutputStream()) {
            BufferedImage image = staticProducer.createImage(code);
            ImageIO.write(image, "jpg", outputStream);
            // 将算术运算结果缓存
            String uuid = IdUtil.simpleUUID();
            String key = uuid + "_" + code;
            CODE_MAP.put(key, new Date());

            Map<String, Object> map = new HashMap<>();
            map.put("uuid", uuid);
            map.put("img", "data:image/gif;base64," + Base64.encode(outputStream.toByteArray()));  // base64编码的图片
            return map;
        } catch (Exception e) {
            e.printStackTrace();
            throw new CustomException("500", "生成验证码错误");
        }
    }

    /**
     * 验证code
     */
    public static void validateCode(String uuid, String code) {
        String key = uuid + "_" + code;
        Date date = CODE_MAP.get(key);
        if (date == null) {
            throw new CustomException("500", "验证码错误");
        }
        // 验证通过，移除验证码缓存
        CODE_MAP.remove(key);
    }

    /**
     * 清理缓存
     */
    public static void removeCodeCache(String key) {
        CODE_MAP.remove(key);
    }

    // 5 分钟扫描一次
    @Scheduled(fixedRate = 5 * 60000)
    public void scanCode() {
        List<String> expireKeys = new ArrayList<>();
        System.out.println("==================验证码缓存定时器开始清理过期验证码，缓存长度：" + CODE_MAP.keySet().size() + "==================");
        CODE_MAP.forEach((k, v) -> {
            if (DateUtil.between(v, new Date(), DateUnit.SECOND) > 300) {  // 大于5分钟 失效
                expireKeys.add(k);
            }
        });
        for (String expireKey : expireKeys) {
            CODE_MAP.remove(expireKey);
        }
        // 设置最大值 1024 到了最大值，缓存全清空
        if (CODE_MAP.size() >= 1024) {
            CODE_MAP.clear();
        }
        System.out.println("========================验证码缓存清理结束，缓存长度：" + CODE_MAP.keySet().size() + "=======================");
    }

}